print("------------ 枚举的定义 ------------")
enum Direction {
    case north
    case east
    case south
    case west
}

var direct: Direction = Direction.west

switch direct {
case Direction.north:
    print("north")
case Direction.east:
    print("east")
case Direction.south:
    print("south")
case Direction.west:
    print("west")
}

print("------------ 枚举的遍历 ------------")
// 遍历枚举需要让枚举遵守CaseIterable协议
enum AnotherDirection: CaseIterable {
    case north
    case east
    case south
    case west
}
let countOfAnotherDirection = AnotherDirection.allCases.count
print("枚举有\(countOfAnotherDirection)个值")

for direct in AnotherDirection.allCases {
    print("AnotherDirection的枚举值: \(direct)")
}

print("------------ 枚举的关联值 ------------")
enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrcode(String)
}
var productBarcode = Barcode.upc(1, 2, 3, 4)
print(productBarcode)
productBarcode = .qrcode("This is a barcode!")
print(productBarcode)

print("------------ 关联值的值绑定(解构赋值) ------------")
productBarcode = Barcode.upc(1, 2, 3, 4)
switch productBarcode {
case .upc(let x, let y, let w, let h):
    print("UPC: \(x), \(y), \(w), \(h)")
case .qrcode(let str):
    print("QRCODE: \(str)")
}

print("------------ 枚举的原始值 ------------")
enum ASCIICharacter: Character {
    case tab = "\t"
    case lineFeed = "\n"
    case enter = "\r"
}
// 自动分配原始值
enum Planet: Int, CaseIterable {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
for p in Planet.allCases {
    print("Planetn的原始值: \(p.rawValue)")
}

enum CompassPoint: String, CaseIterable {
    case north, south, east, west
}
for c in CompassPoint.allCases {
    print("CompassPoint的原始值: \(c.rawValue)")
}

print("------------ 用原始值初始化一个枚举值 ------------")
// 原始值初始化一个枚举值出来是一个可选项
if let p = Planet(rawValue: 7) {
    print(p)
} else {
    print("初始化失败了")
}

print("------------ 递归枚举 ------------")
// 需要使用indirect声明
indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

let product = ArithmeticExpression.multiplication(ArithmeticExpression.addition(ArithmeticExpression.number(1), ArithmeticExpression.number(3)), ArithmeticExpression.number(2))

func evalueate(_ expression: ArithmeticExpression) -> Int {
    switch expression {
    case let .number(value):
        return value
    case let .addition(first, second):
        return evalueate(first) + evalueate(second)
    case let .multiplication(first, second):
        return evalueate(first) * evalueate(second)
    }
}

print(evalueate(product))
